﻿using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using CommonLibraries.DeviceLibrary;
using CommonLibraries.DeviceLibrary.Helpers;
using Distribution.General;
using Distribution.Service;
using DistributionApplication.Interface;
using DistributionApplication.Presenter;
using Entities;

namespace DistributionApplication
{
    /// <summary>
    /// Base form which all the others inherit.
    /// </summary>
    public partial class frmBase : Form, IBase
    {
        private BasePresenter m_presenter;

        #region External Methods
        /// <summary>
        /// Returns total number of bytes, number of free bytes and free bytes available for a given path.
        /// </summary>
        [DllImport("coredll")]
        public static extern int GetDiskFreeSpaceEx(string lpDirectoryName, ref long lpFreeBytesAvailable, ref long lpTotalNumberOfBytes, ref long lpTotalNumberOfFreeBytes);
        #endregion

        #region Private and Protected Members
        //To be used in conjunction with the corresponding properties to control menu offset
        private Int32 m_LButtonMenuXOffset = 0;
        private Int32 m_LButtonMenuYOffset = 0;
        private Int32 m_RButtonMenuXOffset = 0;
        private Int32 m_RButtonMenuYOffset = 0;
        protected GPS m_GPS = GPS.GetInstance();
        protected Handheld m_Handheld = Handheld.GetInstance();
        protected static ESettings Settings {get;set;}

        //WARNING: These values were calculated by observing and comparing 'Remaining Power' in the Power
        //dialog in the Control Panel and the results retrieved from m_Handheld.BatteryLevel. For that reason
        //they should be considered as approximate values.
        const int m_MinBatteryLevel = 6500;
        const int m_MaxBatteryLevel = 8230;

        #endregion

        #region Public Properties
        
        public Int32 LButtonMenuXOffset
        {
            get { return m_LButtonMenuXOffset; }
            set { m_LButtonMenuXOffset = value; }
        }
        public Int32 LButtonMenuYOffset
        {
            get { return m_LButtonMenuYOffset; }
            set { m_LButtonMenuYOffset = value; }
        }
        public Int32 RButtonMenuXOffset
        {
            get { return m_RButtonMenuXOffset; }
            set { m_RButtonMenuXOffset = value; }
        }
        public Int32 RButtonMenuYOffset
        {
            get { return m_RButtonMenuYOffset; }
            set { m_RButtonMenuYOffset = value; }
        }

        #endregion

        #region IBase Members

        public string Title
        {
            set { lblTitle.Text = value; }
        }

        public string RButtonText
        {
            set
            {
                lblRButtonText.BringToFront();
                lblRButtonText.Text = value;
                lblRButton.Text = "";
                lblRButton.SendToBack();
            }
        }

        public string LButtonText
        {
            set
            {
                lblLButtonText.BringToFront();
                lblLButtonText.Text = value;
                lblLButton.Text = "";
                lblLButton.SendToBack();
            }
        }

        /// <summary>
        /// Shows a 'Loading' screen
        /// </summary>
        /// <summary>
        /// Hides the 'Loading' screen (replacing the title)
        /// </summary>
        public void ShowLoading()
        {
            lblTitle.Text = "Loading...";
            lblLoading.Visible = true;
            lblLoading.BringToFront();
            pbxHourglass.Visible = true;
            pbxHourglass.BringToFront();
        }

        public void HideLoading(string formTitle)
        {
            lblTitle.Text = formTitle;
            lblLoading.Visible = false;
            pbxHourglass.Visible = false;
            SetCorrectOrder();

            
        }

        public int SolutionStatus
        {
            set
            {
                lblSolutionStatus.BackColor = m_presenter.SetStatus(value);
                lblSolutionStatus.Tag = value;
                lblSolutionStatus.Update();
                Application.DoEvents();
            }
        }
        public int DiskStatus
        {
            set
            {
                lblDiskStatus.BackColor = m_presenter.SetStatus(value);
                lblDiskStatus.Tag = value;
                lblDiskStatus.Update();
                Application.DoEvents();
            }
        }
        public int BatteryStatus
        {
            set
            {
                lblBatteryStatus.BackColor = m_presenter.SetStatus(value);
                lblBatteryStatus.Tag = value;
                lblBatteryStatus.Update();
                Application.DoEvents();
            }
        }

        public DialogResult ShowMessage(string message, string title)
        {
           return MessageBox.Show(message, title);
        }

        #endregion

        public frmBase()
        {
            InitializeComponent();
            m_presenter = new BasePresenter(this);

            if (Settings == null) 
            {
                Settings = LSetting.GetAll();
                m_GPS.ChangeToMode((ReceptionMode)Settings.ReceptionMode.Value);
            }
        }

        /// <summary>
        /// Handler for Form Load event
        /// </summary>
        private void frmBase_Load(object sender, EventArgs e)
        {
            SetCorrectOrder();

            m_presenter.Setup();

            GPSOn();

            m_GPS.HasSolutionChanged += m_GPS_HasSolutionChanged;

            //Starts disk status
            m_presenter.CheckDisk();

            //Starts battery status
            m_presenter.CheckBattery();
        }

        /// <summary>
        /// Set correct Z-Order
        /// </summary>
        protected void SetCorrectOrder()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            pbxHeader.SendToBack();
            lblLButtonText.BringToFront();
            lblRButtonText.BringToFront();
            lblLButton.BringToFront();
            lblRButton.BringToFront();
            lblBatteryStatus.BringToFront();
            lblDiskStatus.BringToFront();
            lblSolutionStatus.BringToFront();
        }

        /// <summary>
        /// Handler for lblLButton Click event
        /// </summary>
        protected virtual void lblLButton_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If this button has a context menu, display it
            if (lblLButton.ContextMenu != null)
                lblLButton.ContextMenu.Show(this, new Point(lblLButton.Left + m_LButtonMenuXOffset, lblLButton.Top - m_LButtonMenuYOffset));
        }
        /// <summary>
        /// Handler for lblRButton Click event
        /// </summary>
        protected virtual void lblRButton_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If this button has a context menu, display it
            if (lblRButton.ContextMenu != null)
                lblRButton.ContextMenu.Show(this, new Point(lblRButton.Left + m_RButtonMenuXOffset, lblRButton.Top - m_RButtonMenuYOffset));
        }
        /// <summary>
        /// Handler for lblLButtonText Click event
        /// </summary>
        private void lblLButtonText_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If button text is clicked, redirect to handler of main button
            lblLButton_Click(sender, e);
        }
        /// <summary>
        /// Handler for lblRButtonText Click event
        /// </summary>
        private void lblRButtonText_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //If button text is clicked, redirect to handler of main button
            lblRButton_Click(sender, e);
        }
        /// <summary>
        /// Handler for lblClose Click event
        /// </summary>
        protected virtual void lblClose_Click(object sender, EventArgs e)
        {

            //Delete temp images and exit the application
            m_presenter.DeleteTemporaryFiles();
            if (MessageBox.Show("Are you sure you want to exit?", PPIConstants.K_AppName, MessageBoxButtons.YesNo, MessageBoxIcon.None, MessageBoxDefaultButton.Button2) == DialogResult.Yes)
                Application.Exit();
        }

        #region GPS
        /// <summary>
        /// Powers GPS on
        /// </summary>
        protected void GPSOn()
        {
            if (m_GPS.PowerState == PowerStates.Off)
            {
                m_GPS.Reset();
                m_GPS.PowerState = PowerStates.On;
            }
        }
        private delegate void SolutionChangedCallback();
        private delegate void ThreadDelegate();
        
        /// <summary>
        /// Handler for m_GPS HasSolutionChanged event
        /// </summary>
        public void m_GPS_HasSolutionChanged(object sender, EventArgs e)
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: GBarzola
            //Last update: -

            try
            {
                //Invoke HasSolutionChanged in a new thread
                Invoke(new ThreadDelegate(this.HasSolutionChanged));
            }
            catch (ObjectDisposedException ex)
            {
                ErrorManager.CreateDebug("BeginInvoke->" + ex.Message);
            }
            //HasSolutionChanged();
        }
        
        /// <summary>
        /// Changes display depending on GPS solution status.
        /// </summary>
        protected void HasSolutionChanged()
        {
            //Created by: GBarzola
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Changes display depending on GPS solution status. To avoid Blinking, solution detection must
            //fail at least 5 times in a row to display a red icon.

            if (InvokeRequired)
            {
                SolutionChangedCallback d = HasSolutionChanged;
                Invoke(d);
            }
            else
            {
                try
                {
                    GPSOn();

                    m_presenter.CheckDisk();
                    m_presenter.CheckBattery();
                    //Starts solution status
                    SolutionStatus = m_GPS.HasSolution ? (Int32)SquareColors.Green : (Int32)SquareColors.Red;
                }
                catch (Exception ex)
                {
                    ErrorManager.CreateDebug("HasSolutionChanged->Problems\n" + ex.Message);
                }
            }
        }
        #endregion

        /// <summary>
        /// Handler for lblBatteryStatus Click event
        /// </summary>
        private void lblBatteryStatus_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Displays battery status details
            m_presenter.ShowBatteryStatus((Int32)lblBatteryStatus.Tag);
        }
        /// <summary>
        /// Handler for lblDiskStatus Click event
        /// </summary>
        private void lblDiskStatus_Click(object sender, EventArgs e)
        {
            //Displays disk status details
            m_presenter.ShowDiskStatus((Int32)lblSolutionStatus.Tag);

        }
        /// <summary>
        /// Handler for lblSolutionStatus Click event
        /// </summary>
        private void lblSolutionStatus_Click(object sender, EventArgs e)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            //Displays solution status details
            try
            {
                switch ((Int32)lblSolutionStatus.Tag)
                {
                    case (Int32)SquareColors.Green:
                        MessageBox.Show("GPS Solution is currently available - " + m_GPS.NmeaGGA.SateliteCount + " satellite(s)", PPIConstants.K_AppName);
                        break;
                    case (Int32)SquareColors.Red:
                        MessageBox.Show("GPS Solution is currently unavailable", PPIConstants.K_AppName);
                        break;
                    default:
                        MessageBox.Show("GPS Solution status is unknown", PPIConstants.K_AppName);
                        break;
                }
            }
            catch
            {
                MessageBox.Show("GPS Solution is currently unavailable", PPIConstants.K_AppName);
            }
        }

        public void SetRContextMenu(ContextMenu menu)
        {
            lblRButton.ContextMenu = menu;
        }
        public void SetLContextMenu(ContextMenu menu)
        {
            lblLButton.ContextMenu = menu;
        }

        #region Battery
        /// <summary>
        /// Returns an approximation of current battery level (almost always the same value as in the Power
        /// dialog in the Control Panel)
        /// </summary>
        protected static double GetEnergyPercentage(Int32 batteryLevel)
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            return Convert.ToDouble((batteryLevel - m_MinBatteryLevel) * 100) / (m_MaxBatteryLevel - m_MinBatteryLevel);
        }
        /// <summary>
        /// Calculates battery level.
        /// 100% - 51% = Good
        /// 50% - 26% = Low
        /// 25% - 1% = Very Low
        /// </summary>
        private void CheckBatteryLevel()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            int _CurrentLoadPercentage = Convert.ToInt32(GetEnergyPercentage(m_Handheld.BatteryLevel));

            if (_CurrentLoadPercentage >= 51 && _CurrentLoadPercentage <= 100)
                BatteryStatus = (int)SquareColors.Green;
            else if (_CurrentLoadPercentage < 51 && _CurrentLoadPercentage > 25)
                BatteryStatus = (int)SquareColors.Yellow;
            else
                BatteryStatus = (int)SquareColors.Red;
        }
        /// <summary>
        /// Returns White if connected to the power cord, or the corresponding status if not.
        /// </summary>
        private void CheckBattery()
        {
            //Created by: VMCoder
            //Creation date: -
            //Last updated by: VMCoder
            //Last update: 2008.04.10

            if (m_Handheld.PowerSource == PowerSources.Battery)
                CheckBatteryLevel();
            else
                BatteryStatus = (int)SquareColors.White;
        }
        #endregion
    }
}
